import { ErrorDialogComponent } from './../shared/error-dialog/error-dialog.component';
import { MatDialog } from '@angular/material';
import { Injectable } from '@angular/core';
import { CookieService } from 'ngx-cookie';
import { Headers, Http, Request, RequestMethod, RequestOptions, Response, ResponseContentType } from '@angular/http';
import { GridOptions } from 'ag-grid/main';
import { Observable } from 'rxjs/Observable';
import { environment } from './../../environments/environment';
import { Router } from '@angular/router';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

import * as _ from 'lodash';
import * as moment from 'moment';

@Injectable()
export class RestService {
  schema: any;
  timestamp = 'TimeStamp';
  // timestamp = '@timestemap';

  hostUrl;
  headers: Headers;
  commonHeaders = new Headers({
     'X-Requested-With': 'XMLHttpRequest',
     'Content-Type': 'application/json'
  });

  private chartQueryMode = false;

  constructor(private http: Http,
              private dialog: MatDialog,
              private router: Router) {
    this.hostUrl = '';

    // reassign credentials, this is allow user to refresh pages
    this.reassignCred2CommonHeaders();

    this.get('webui/schema.json').subscribe(data => {
      localStorage.setItem('schema', JSON.stringify(data.schema));
      this.schema = data.schema;
    }, error => {
      this.schema = this.getSchema();
    });
  }

  setChartQueryMode(isQuery) {
    this.chartQueryMode = isQuery;
  }

  getChartQueryMode() {
    return this.chartQueryMode;
  }

  isDebugging() {
    return _.startsWith(window.location.hostname, 'localhost');
  }

  public login(user: any): any {
    const cred = btoa(user.userName + ':' + user.userPassword);

    this.headers = user ? (new Headers({
      'authorization': 'Basic ' + cred,
      'X-Requested-With': 'XMLHttpRequest'
    })) : (new Headers());
    this.commonHeaders.set('ecryptedAuth', cred);

    return this.http.post(this.hostUrl + 'login', {userName: user.userName}, {headers: this.headers})
      .map(res => res.json())
      .catch(this.handleDetailedError);
  }

  private reassignCred2CommonHeaders() {
    let cred = this.commonHeaders.get('ecryptedAuth');
    if (cred) {
      return;
    }

    cred = this.getEnCred();
    if (cred) {
      this.commonHeaders.append('ecryptedAuth', cred);
    }
  }

  public getRaw(suffix: string) {
    return this.http.get(this.hostUrl + suffix, {headers: this.commonHeaders});
  }

  public get(suffix: string) {
    return this.http.get(this.hostUrl + suffix, {headers: this.commonHeaders})
      .map(res => res.json())
      .catch(this.handleDetailedError);
  }

  public post(suffix: string, body: any) {
    return this.http.post(this.hostUrl + suffix, body, {headers: this.commonHeaders})
      .map(res => res.json())
      .catch(this.handleDetailedError);
  }

  public put(suffix: string, body: any) {
    return this.http.put(this.hostUrl + suffix, body, {headers: this.commonHeaders});
  }

  public patch(suffix: string, body: any) {
    return this.http.patch(this.hostUrl + suffix, body, {headers: this.commonHeaders});
  }

  public delete(suffix: string) {
    return this.http.delete(this.hostUrl + suffix, {headers: this.commonHeaders});
  }

  /**
   * To extrace data from RPC response.
   */
  private extractData(res: Response) {
    const body = res.json();
    if (!_.isEmpty(body)) {
      return _.values(body)[0];
    }
  }

  /**
   * To return detailed data from response
   */
  private extractRowData(res: Response) {
    const body = res.json();
    if (!_.isEmpty(body)) {
      return _.values(body);
    }
  }

  /**
   * This is to return detailed error reponse.
   */
  private handleDetailedError(error: Response | any) {
    let body: {};
    if (error instanceof Response) {
      const contentType = error.headers.get('content-type');
      if (contentType &&
          (contentType.indexOf('application/json') !== -1 ||
           contentType.indexOf('application/yang.errors+json') !== -1)) {
        body = error.json() || {};
      } else {
        body = error;
      }
    } else {
      body = error;
    }

    return Observable.throw(body);
  }

  // We set local storage data here since all components need to inject this service.
  cleanupLocalStorage() {
    sessionStorage.clear();
    // localStorage.clear();
  }

  // Save the user info
  saveUser(item) {
    sessionStorage.setItem('user', JSON.stringify(item));
  }

  updateUser(item) {
    const user = this.getUser();
    _.assign(user, item);

    this.saveUser(user);
  }

  getUser() {
    const item = JSON.parse(sessionStorage.getItem('user'));
    return item ? item : {};
  }

  saveEnCred(enCredString) {
    sessionStorage.setItem('encred', enCredString);
  }

  getEnCred() {
    return sessionStorage.getItem('encred');
  }

  getSchema() {
    if (this.schema) {
      return this.schema;
    }

    return JSON.parse(localStorage.getItem('schema'));
  }

  getTable(tableId) {
    const schema = this.getSchema();
    if (!schema) {
      return {};
    }

    const table = schema[tableId];
    return table ? table : {};
  }

  getTableLabel(tableId) {
    const schema = this.getSchema();
    if (!schema) {
      return tableId;
    }

    const table = schema[tableId];
    if (!table || !table.elements) {
      return tableId;
    }

    return table.name;
  }

  getGeneralGridOptions() {
    return <GridOptions> {
      enableFilter: false,
      enableColResize: true,
      enableSorting: true,
      suppressRowClickSelection: false,
      rowSelection: 'multiple',
      rowHeight: 42,
      headerHeight: 42,
      overlayNoRowsTemplate: '<span class="csf-overlay">没有相关数据</span>',
      overlayLoadingTemplate: '<span class="csf-overlay">数据加载中...</span>'
    };
  }

  buildGridColumns(tableId) {
    const schema = this.getSchema();
    if (!schema) {
      return [];
    }

    const table = schema[tableId];
    if (!table || !table.elements) {
      return [];
    }

    const columnDefs = [];
    columnDefs.push({
      headerName: '列车号',
      field: 'train',
      width: 90
    }, {
      headerName: '更新时间',
      field: this.timestamp,
      width: 160
    });

    table.elements.forEach(column => {
      columnDefs.push({
        headerName: this.getFieldHeaderName(column),
        field: column.id
      });
    });

    return columnDefs;
  }

  getFieldHeaderName(item) {
    if (item.value && item.value.units && item.value.units !== '1') {
      return item.name + ' (' + item.value.units + ')';
    } else {
      return item.name;
    }
  }

  addCheckboxColumn(columnDefs) {
    columnDefs.push({
      headerName: '',
      headerCheckboxSelection: true,
      cellClass: 'selection-column',
      suppressMenu: true,
      suppressSorting: true,
      suppressSizeToFit: true,
      suppressMovable: true,
      suppressFilter: true,
      suppressResize: true,
      suppressNavigable: true,
      field: 'columnCheckbox',
      checkboxSelection: true,
      pinned: 'left',
      width: 30
    });
  }

  getFaults(data) {
    if (!this.schema) {
      console.log('Failed to get faults because of empty schema!');
      return [];
    }

    const table = this.schema['FaultData'];
    if (!table || !table.elements) {
      console.log('Failed to get faults table in schema!');
      return [];
    }

    const faults = [];
    table.elements.forEach(element => {
      // if (data[element.id] == 1) {
        // got the fault, put it in array
        faults.push(element.name);
      // }
    });

    return faults;
  }

  getUpdatedTime(row) {
    if (_.isNumber(row[this.timestamp])) {
      return moment(row[this.timestamp] * 1000).format('YYYY-MM-DD HH:mm:ss');
    } else {
      return row[this.timestamp];
    }
  }

  getUpdatedDateTime(row) {
    if (_.isNumber(row[this.timestamp])) {
      return moment(row[this.timestamp] * 1000).toDate().getTime();
    } else {
      return row[this.timestamp];
    }
  }

  openErrorDialog(message: string) {
    this.dialog.open(ErrorDialogComponent, {
      width: '400px',
      disableClose: true,
      data: {
        message: message
      }
    });
  }
}
